import "core-js/modules/es.error.cause.js";
import "core-js/modules/es.array.push.js";
import "core-js/modules/esnext.iterator.constructor.js";
import "core-js/modules/esnext.iterator.find.js";
import "core-js/modules/esnext.iterator.for-each.js";
import "core-js/modules/esnext.iterator.reduce.js";
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import { BaseAction } from "./_base.mjs";
import { deepClone } from "../../../helpers/object.mjs";
/**
 * Action that tracks data changes.
 *
 * @class DataChangeAction
 * @private
 */
export class DataChangeAction extends BaseAction {
  constructor(_ref) {
    let {
      changes,
      selected,
      countCols,
      countRows
    } = _ref;
    super('change');
    /**
     * @param {Array} changes 2D array containing information about each of the edited cells.
     */
    _defineProperty(this, "changes", void 0);
    /**
     * @param {number[]} selected The cell selection.
     */
    _defineProperty(this, "selected", void 0);
    /**
     * @param {number} countCols The number of columns before data change.
     */
    _defineProperty(this, "countCols", void 0);
    /**
     * @param {number} countRows The number of rows before data change.
     */
    _defineProperty(this, "countRows", void 0);
    this.changes = changes;
    this.selected = selected;
    this.countCols = countCols;
    this.countRows = countRows;
  }
  static startRegisteringEvents(hot, undoRedoPlugin) {
    hot.addHook('beforeChange', function (changes, source) {
      const changesLen = changes && changes.length;
      if (!changesLen) {
        return;
      }
      const hasDifferences = changes.find(change => {
        const [,, oldValue, newValue] = change;
        return oldValue !== newValue;
      });
      if (!hasDifferences) {
        return;
      }
      const wrappedAction = () => {
        const clonedChanges = changes.reduce((arr, change) => {
          arr.push([...change]);
          return arr;
        }, []);
        clonedChanges.forEach(change => {
          change[1] = hot.propToCol(change[1]);
        });
        const selected = changesLen > 1 ? this.getSelected() : [[clonedChanges[0][0], clonedChanges[0][1]]];
        return new DataChangeAction({
          changes: clonedChanges,
          selected,
          countCols: hot.countCols(),
          countRows: hot.countRows()
        });
      };
      undoRedoPlugin.done(wrappedAction, source);
    });
  }

  /**
   * @param {Core} hot The Handsontable instance.
   * @param {function(): void} undoneCallback The callback to be called after the action is undone.
   */
  undo(hot, undoneCallback) {
    const data = deepClone(this.changes);
    for (let i = 0, len = data.length; i < len; i++) {
      data[i].splice(3, 1);
    }
    hot.addHookOnce('afterChange', () => {
      const rowsToRemove = hot.countRows() - this.countRows;
      if (rowsToRemove > 0) {
        hot.alter('remove_row', null, rowsToRemove, 'UndoRedo.undo');
      }
      const columnsToRemove = hot.countCols() - this.countCols;
      if (columnsToRemove > 0 && hot.isColumnModificationAllowed()) {
        hot.alter('remove_col', null, columnsToRemove, 'UndoRedo.undo');
      }
      hot.scrollToFocusedCell();
      hot.selectCells(this.selected, false, false);
      undoneCallback();
    });
    hot.setDataAtCell(data, null, null, 'UndoRedo.undo');
  }

  /**
   * @param {Core} hot The Handsontable instance.
   * @param {function(): void} redoneCallback The callback to be called after the action is redone.
   */
  redo(hot, redoneCallback) {
    const data = deepClone(this.changes);
    for (let i = 0, len = data.length; i < len; i++) {
      data[i].splice(2, 1);
    }
    hot.addHookOnce('afterChange', () => {
      hot.selectCells(this.selected, false, false);
      redoneCallback();
    });
    hot.setDataAtCell(data, null, null, 'UndoRedo.redo');
  }
}